1
性能瓶颈解析:为何要扩展 NumPy?
AI018Lesson 5
00:00

尽管 NumPy 基于 C 语言构建,但某些计算密集型算法仍会遇到 向量化瓶颈。当 Python 动态特性的固有延迟超过高级抽象带来的优势时,这种情况就会发生。

1. 解释器开销与对象封装

标准 Python 循环中的每一次迭代都涉及动态类型检查和引用计数。即使使用 NumPy 标量,也将原始的 C 数据封装为 Python 对象也会在诸如 $\text{logit}(p) = \log(p/(1-p))$ 的函数中造成巨大瓶颈。在 C 中处理边界情况的速度要快得多:

>>> logit(0) -> -inf
>>> logit(1) -> inf
>>> logit(2) -> nan
>>> logit(-2) -> nan

2. 中间数组膨胀

纯 NumPy 表达式会为每个子操作创建临时内存缓冲区。通过 C-API 扩展可实现 内核融合,即在单次遍历中完成 logit 变换,无需额外的内存开销。

3. 空间依赖性

涉及邻域访问模式的操作,例如二维模板:

$$B(I, J) = A(I, J) + (A(I-1, J) + A(I+1, J) + A(I, J-1) + A(I, J+1)) \cdot 0.5D0 + (A(I-1, J-1) + A(I-1, J+1) + A(I+1, J-1) + A(I+1, J+1)) \cdot 0.25D0$$

如果不进行冗余的内存复制,仅通过切片很难高效表达。C 扩展允许直接进行缓存对齐的指针运算。

main.py
TERMINALbash — 80x24
> Ready. Click "Run" to execute.
>